library(MASS)
library(dplyr)
The following variable screening method is called stepwise regression. This type of model selection adds and drops variables in the model until it finds the one with the most significant variables in it. The measure it uses to predict significance of the chosen variables is the AIC, this number gets smaller and smaller as more significant variables are added and then also penalizes the models for having too many variables in it.
We wanted to predict a teams post-season conference ranking with pre-season statistics, aquired from a large dataset being used for a senior thesis.
X_CFBRversionSEC <- X_CFBRversion %>%
filter(SEC == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionSEC), direction = c("both"))
X_CFBRversionACC <- X_CFBRversion %>%
filter(ACC == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionACC), direction = c("both"))
X_CFBRversionBigTen <- X_CFBRversion %>%
filter(BigTen == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionBigTen), direction = c("both"))
X_CFBRversionPacTen <- X_CFBRversion %>%
filter(PacTen == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionPacTen), direction = c("both"))
X_CFBRversionBigTwelve <- X_CFBRversion %>%
filter(BigTwelve == 1)
#Stepwise Regression
sw<-step(lm(EPSNrank~FrNbrRecruits+Fr5star+Fr4star+Fr3star+Fravg+Sonbrrecruits+So5star+So4star+So3star+Soavg+Jrnbrrecruits+Jr5star+Jr4star+Jr3star+Jravg+Srnbrrecruits+Sr5star+Sr4star+Sr3star+Sravg+Rssrnbrrecruits+Rssr5star+Rssr4star+Rssr3star+Rssravg+z_lysagarin+z_tyasagarin+retoff+retdef+qbret+bowl+bowlwin+coachexp_school+coachexp_total+BigTen+SEC+BigTwelve+ACC+PacTen+Bigeast, data = X_CFBRversionBigTwelve), direction = c("both"))
So through this process, we found that different variables were deemed significant in different conferences. Essentially it means that different things are necessary to be successful relative to the other teams in your conference, based on a given conference.
SEC: “Fr5star”,“Fr4star”,“So4star”,“Soavg”,“Jrnbrrecruits”,“Jr5star”,“Jr4star”,“Rssr5star”,“Rssr4star”,“z_lysagarin”,“coachexp_school”,“coachexp_total”
ACC:“FrNbrRecruits” , “Fr4star” , “Sonbrrecruits”, “Jrnbrrecruits”, “Jr5star”, “Jr4star”, “Jr3star”, “Jravg”, “Rssr4star”, “z_lysagarin”,“retoff”, “bowl” ,“coachexp_total”
BigTen: “FrNbrRecruits”,“Fr3star”,“So4star”,“Jrnbrrecruits”,“Jr5star”,“Jr4star”,“Jr3star”,“Jravg”,“Srnbrrecruits”,“Sr3star”,“z_lysagarin”,“coachexp_total”
PacTen:“FrNbrRecruits” , “Fr4star” , “Sonbrrecruits”, “So4star”, “Soavg”, “Jrnbrrecruits” , “Jravg” , “Sr3star” , “Rssrnbrrecruits” , “Rssr5star” , “Rssr4star” , “Rssr3star” , “Rssravg” , “z_lysagarin” , “z_tyasagarin” , “retdef” , “qbret” , “coachexp_school” , “coachexp_total” , “Sravg”
BigTwelve:“FrNbrRecruits”, “Fr4star”, “Fr3star”, “Fravg”, “Sonbrrecruits”,“Soavg” , “Jrnbrrecruits” , “Jr5star” , “Srnbrrecruits” , “Rssrnbrrecruits” , “Rssravg” , “z_lysagarin” , “coachexp_school” , “coachexp_total”
Next, we subsetted the data for each conference so it only contained the variables that were deemed important in the variable screening process.
This facilitated the process of creating a function that will take in a string as a conference (i.e. “SEC”) and a year and outputs that conference’s rankings for that year
The function subsets the data into the conference you specify, and then subsets it into 2 datasets: one that contains all the data from every year except the year you specified (this is your training data), and one that is solely the data of year you specified (this is your test data). The multliple linear regression model is fit based on the training data, and then you use that model to predict the test data.
SECsubset <- as.data.frame(X_CFBRversion[,c(1,2,3,7,8,14,16,18,19,20,31,32,38,46,47,50)])
SECsubset<- SECsubset %>%
filter(SEC == 1)
ACCsubset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,8,12,18,19,20,21,22,32,38,41,44,47,52)])
ACCsubset<- ACCsubset %>%
filter(ACC == 1)
PAC10subset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,8,12,14,16,18,22,27,30,31,32,33,34,38,40,42,43,46,47,28,53)])
PAC10subset<- PAC10subset %>%
filter(PacTen == 1)
Big10subset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,9,14,18,19,20,21,22,24,27,38,47,49)])
Big10subset<- Big10subset %>%
filter(BigTen == 1)
Big12subset <- as.data.frame(X_CFBRversion[,c(1,2,3,6,8,9,10,12,16,18,19,24,30,34,38,46,47,51)])
Big12subset<- Big12subset %>%
filter(BigTwelve == 1)
predRank<- function(x,y)
{
dat<-subset(SECsubset, SECsubset$Year != y)
newdat<-subset(SECsubset, SECsubset$Year == y)
if(x=="SEC") {
colnames(dat) <- c("Team","Year","EPSNrank","Fr5star","Fr4star","So4star","Soavg","Jrnbrrecruits","Jr5star","Jr4star","Rssr5star","Rssr4star","z_lysagarin","coachexp_school","coachexp_total")
sw<- lm(EPSNrank ~ Fr5star + Fr4star + So4star + Soavg + Jrnbrrecruits +
Jr5star + Jr4star + Rssr5star + Rssr4star + z_lysagarin +
coachexp_school + coachexp_total, data = dat)
preds<-predict(sw, newdata = newdat)
predset<-t(rbind(newdat$Team,newdat$EPSNrank,preds))
preddf<-as.data.frame(predset)
}
if(x=="ACC") {
dat<-subset(ACCsubset, ACCsubset$Year != y)
newdat<-subset(ACCsubset, ACCsubset$Year == y)
colnames(dat) <- c("Team","Year","EPSNrank", "FrNbrRecruits" , "Fr4star" , "Sonbrrecruits", "Jrnbrrecruits", "Jr5star", "Jr4star", "Jr3star", "Jravg", "Rssr4star", "z_lysagarin","retoff", "bowl" ,"coachexp_total")
fw<- lm(EPSNrank ~ FrNbrRecruits + Fr4star + Sonbrrecruits + Jrnbrrecruits +
Jr5star + Jr4star + Jr3star + Jravg + Rssr4star + z_lysagarin +
retoff + bowl + coachexp_total, data = dat)
preds<-predict(fw, newdata = newdat)
predset<-t(rbind(newdat$Team, newdat$EPSNrank,preds))
preddf<-as.data.frame(predset)
}
if(x=="BigTen"){
dat<-subset(Big10subset, Big10subset$Year != y)
newdat<-subset(Big10subset, Big10subset$Year == y)
colnames(dat) <- c("Team","Year","EPSNrank","FrNbrRecruits","Fr3star","So4star","Jrnbrrecruits","Jr5star","Jr4star","Jr3star","Jravg","Srnbrrecruits","Sr3star","z_lysagarin","coachexp_total")
bw <- lm(EPSNrank ~ FrNbrRecruits + Fr3star + So4star + Jrnbrrecruits +
Jr5star + Jr4star + Jr3star + Jravg + Srnbrrecruits + Sr3star +
z_lysagarin + coachexp_total, data = dat)
preds<-predict(bw, newdata = newdat)
predset<-t(rbind(newdat$Team,newdat$EPSNrank,preds))
preddf<-as.data.frame(predset)
}
if(x=="PacTen"){
dat<-subset(PAC10subset, PAC10subset$Year != y)
newdat<-subset(PAC10subset, PAC10subset$Year == y)
colnames(dat) <- c("Team","Year","EPSNrank", "FrNbrRecruits" , "Fr4star" , "Sonbrrecruits", "So4star", "Soavg", "Jrnbrrecruits" , "Jravg" , "Sr3star" , "Rssrnbrrecruits" , "Rssr5star" , "Rssr4star" , "Rssr3star" , "Rssravg" , "z_lysagarin" , "z_tyasagarin" , "retdef" , "qbret" , "coachexp_school" , "coachexp_total" ,
"Sravg")
bw <- lm(EPSNrank ~ FrNbrRecruits + Fr4star + Sonbrrecruits + So4star +
Soavg + Jrnbrrecruits + Jravg + Sr3star + Rssrnbrrecruits +
Rssr5star + Rssr4star + Rssr3star + Rssravg + z_lysagarin +
z_tyasagarin + retdef + qbret + coachexp_school + coachexp_total +
Sravg, data = dat)
preds<-predict(bw, newdata = newdat)
predset<-t(rbind(newdat$Team,newdat$EPSNrank,preds))
preddf<-as.data.frame(predset)
}
if(x =="BigTwelve"){
dat<-subset(Big12subset, Big12subset$Year != y)
newdat<-subset(Big12subset, Big12subset$Year == y)
colnames(dat) <- c("Team","Year","EPSNrank","FrNbrRecruits", "Fr4star", "Fr3star", "Fravg", "Sonbrrecruits","Soavg" , "Jrnbrrecruits" , "Jr5star" , "Srnbrrecruits" , "Rssrnbrrecruits" , "Rssravg" , "z_lysagarin" , "coachexp_school" , "coachexp_total")
fw<-lm(EPSNrank ~ FrNbrRecruits + Fr4star + Fr3star + Fravg + Sonbrrecruits +
Soavg + Jrnbrrecruits + Jr5star + Srnbrrecruits + Rssrnbrrecruits +
Rssravg + z_lysagarin + coachexp_school + coachexp_total, data = dat)
preds<-predict(fw, newdata = newdat)
predset<-t(rbind(newdat$Team, newdat$EPSNrank,preds))
preddf<-as.data.frame(predset)
}
preddf$V2<-as.numeric(as.character(preddf$V2))
preddf$preds<-as.numeric(as.character(preddf$preds))
return(preddf)
}
Next, we predicted the conference rankings for the 2018 season using the function we created above. The results are below. One limitation is that the function predicted the rankings as doubles instead of integers. Therefore, we just ordered the predictions least to greatest, as you can see below.
SEC<-predRank("SEC",2018)
ACC<-predRank("ACC",2018)
BigTen<-predRank("BigTen",2018)
PacTen<-predRank("PacTen",2018)
BigTwelve<-predRank("BigTwelve",2018)
SEC<-SEC[order(SEC$preds),]
SEC
V1 V2 preds
149 Georgia 2 0.7483953
151 LSU 4 3.8811658
145 Alabama 1 5.6032631
150 Kentucky 5 5.8993797
157 Texas A&M 6 7.1220021
154 Ole Miss 13 7.3828862
155 South Carolina 9 7.4111542
147 Auburn 10 7.8791257
153 Missouri 7 8.3805134
152 Mississippi State 8 9.0233377
156 Tennessee 12 9.3217204
146 Arkansas 14 10.2480061
158 Vanderbilt 11 10.4361920
148 Florida 3 11.4028449
ACC<-ACC[order(ACC$preds),]
ACC
V1 V2 preds
149 Miami-FL 8 1.834273
146 Florida State 12 1.880734
155 Virginia Tech 9 3.276114
150 NC State 4 4.534099
148 Louisville 14 4.671640
156 Wake Forest 11 4.825418
154 Virginia 7 4.908386
144 Clemson 1 4.975559
143 Boston College 6 5.566071
145 Duke 10 8.241210
147 Georgia Tech 5 9.086959
153 Syracuse 2 9.579264
151 North Carolina 13 10.772782
152 Pittsburgh 3 12.379287
BigTen<-BigTen[order(BigTen$preds),]
BigTen
V1 V2 preds
147 Penn State 4 -0.4226229
142 Michigan State 7 2.9731629
146 Ohio State 1 4.0818182
141 Michigan 2 5.3926006
139 Iowa 5 5.5232166
144 Nebraska 11 7.4059580
148 Purdue 8 8.8154271
145 Northwestern 3 8.9978007
143 Minnesota 9 9.5228485
137 Illinois 13 9.8637852
138 Indiana 12 10.1719705
140 Maryland 10 10.5101409
149 Rutgers 14 12.1588026
150 Wisconsin 6 NA
PacTen<-PacTen[order(PacTen$preds),]
PacTen
V1 V2 preds
135 Washington 2 4.498936
126 Arizona State 6 5.861611
125 Arizona 8 6.033062
131 Southern Cal 9 6.131612
127 California 7 6.304335
132 Stanford 4 7.533845
129 Oregon 5 7.898436
128 Colorado 11 8.350038
130 Oregon State 12 8.539411
136 Washington St. 1 8.610382
133 UCLA 10 8.979491
134 Utah 3 9.280296
BigTwelve<-BigTwelve[order(BigTwelve$preds),]
BigTwelve
V1 V2 preds
123 Oklahoma 1 3.572277
122 Kansas State 9 3.915932
124 Oklahoma State 7 4.489035
126 Texas 2 4.738465
120 Iowa State 4 5.826364
128 West Virginia 3 6.952349
127 Texas Tech 8 7.402782
125 TCU 6 8.590376
119 Baylor 5 9.810153
121 Kansas 10 10.416551
Our predictions weren’t very accuarate, however usually the predicted top ranked team is in the top 5 (ish).
We also used another method of predicting, decision trees. We wrote a very similar function to predict a given seasons conference rankings for each conference. The function takes in a string as a conference (i.e. “SEC”) and a year and predicts that conference’s rankings for that year, just like the one above but based on the decision tree model.
There is a new decision tree created for each conference. The process for this function is essentially the exact same as the one above, except decision trees are used to predict.
One thing to note about the tree diagram is that it predicts the ranking in factors essentially. Therefore a lot of “ties” show up in the predictions, as you will see below.


SECTree<-treePredRank("SEC",2018)
ACCTree<-treePredRank("ACC",2018)
BigTenTree<-treePredRank("BigTen",2018)

PacTenTree<-treePredRank("PacTen",2018)

BigTwelveTree<-treePredRank("BigTwelve",2018)

These predicitions are also not very accurate. However, the ties are interesting because you can see how teams differ in the post-season that were predicted to perform the same.
Overall, preseason statistics dont seem to be a very good predictor of post-season conference rankings, whether you are using multilple linear regression and variable screening methods or decision trees.
An important result we attained was how different conferences yield different predictors of success.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyLCBtZXNzYWdlPVRSVUV9CmxpYnJhcnkoTUFTUykKbGlicmFyeShkcGx5cikKYGBgClRoZSBmb2xsb3dpbmcgdmFyaWFibGUgc2NyZWVuaW5nIG1ldGhvZCBpcyBjYWxsZWQgc3RlcHdpc2UgcmVncmVzc2lvbi4gVGhpcyB0eXBlIG9mIG1vZGVsIHNlbGVjdGlvbiBhZGRzIGFuZCBkcm9wcyB2YXJpYWJsZXMgaW4gdGhlIG1vZGVsIHVudGlsIGl0IGZpbmRzIHRoZSBvbmUgd2l0aCB0aGUgbW9zdCBzaWduaWZpY2FudCB2YXJpYWJsZXMgaW4gaXQuIFRoZSBtZWFzdXJlIGl0IHVzZXMgdG8gcHJlZGljdCBzaWduaWZpY2FuY2Ugb2YgdGhlIGNob3NlbiB2YXJpYWJsZXMgaXMgdGhlIEFJQywgdGhpcyBudW1iZXIgZ2V0cyBzbWFsbGVyIGFuZCBzbWFsbGVyIGFzIG1vcmUgc2lnbmlmaWNhbnQgdmFyaWFibGVzIGFyZSBhZGRlZCBhbmQgdGhlbiBhbHNvIHBlbmFsaXplcyB0aGUgbW9kZWxzIGZvciBoYXZpbmcgdG9vIG1hbnkgdmFyaWFibGVzIGluIGl0LgoKV2Ugd2FudGVkIHRvIHByZWRpY3QgYSB0ZWFtcyBwb3N0LXNlYXNvbiBjb25mZXJlbmNlIHJhbmtpbmcgd2l0aCBwcmUtc2Vhc29uIHN0YXRpc3RpY3MsIGFxdWlyZWQgZnJvbSBhIGxhcmdlIGRhdGFzZXQgYmVpbmcgdXNlZCBmb3IgYSBzZW5pb3IgdGhlc2lzLiAKCmBgYHtyfQpYX0NGQlJ2ZXJzaW9uU0VDIDwtIFhfQ0ZCUnZlcnNpb24gJT4lCiAgZmlsdGVyKFNFQyA9PSAxKQojU3RlcHdpc2UgUmVncmVzc2lvbgpzdzwtc3RlcChsbShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcitSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gWF9DRkJSdmVyc2lvblNFQyksIGRpcmVjdGlvbiA9IGMoImJvdGgiKSkKCgpgYGAKCmBgYHtyfQpYX0NGQlJ2ZXJzaW9uQUNDIDwtIFhfQ0ZCUnZlcnNpb24gJT4lCiAgZmlsdGVyKEFDQyA9PSAxKQojU3RlcHdpc2UgUmVncmVzc2lvbgpzdzwtc3RlcChsbShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcitSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gWF9DRkJSdmVyc2lvbkFDQyksIGRpcmVjdGlvbiA9IGMoImJvdGgiKSkKYGBgCgpgYGB7cn0KWF9DRkJSdmVyc2lvbkJpZ1RlbiA8LSBYX0NGQlJ2ZXJzaW9uICU+JQogIGZpbHRlcihCaWdUZW4gPT0gMSkKI1N0ZXB3aXNlIFJlZ3Jlc3Npb24Kc3c8LXN0ZXAobG0oRVBTTnJhbmt+RnJOYnJSZWNydWl0cytGcjVzdGFyK0ZyNHN0YXIrRnIzc3RhcitGcmF2ZytTb25icnJlY3J1aXRzK1NvNXN0YXIrU280c3RhcitTbzNzdGFyK1NvYXZnK0pybmJycmVjcnVpdHMrSnI1c3RhcitKcjRzdGFyK0pyM3N0YXIrSnJhdmcrU3JuYnJyZWNydWl0cytTcjVzdGFyK1NyNHN0YXIrU3Izc3RhcitTcmF2ZytSc3NybmJycmVjcnVpdHMrUnNzcjVzdGFyK1Jzc3I0c3RhcitSc3NyM3N0YXIrUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IFhfQ0ZCUnZlcnNpb25CaWdUZW4pLCBkaXJlY3Rpb24gPSBjKCJib3RoIikpCmBgYAoKYGBge3J9ClhfQ0ZCUnZlcnNpb25QYWNUZW4gPC0gWF9DRkJSdmVyc2lvbiAlPiUKICBmaWx0ZXIoUGFjVGVuID09IDEpCiNTdGVwd2lzZSBSZWdyZXNzaW9uCnN3PC1zdGVwKGxtKEVQU05yYW5rfkZyTmJyUmVjcnVpdHMrRnI1c3RhcitGcjRzdGFyK0ZyM3N0YXIrRnJhdmcrU29uYnJyZWNydWl0cytTbzVzdGFyK1NvNHN0YXIrU28zc3RhcitTb2F2ZytKcm5icnJlY3J1aXRzK0pyNXN0YXIrSnI0c3RhcitKcjNzdGFyK0pyYXZnK1NybmJycmVjcnVpdHMrU3I1c3RhcitTcjRzdGFyK1NyM3N0YXIrU3JhdmcrUnNzcm5icnJlY3J1aXRzK1Jzc3I1c3RhcitSc3NyNHN0YXIrUnNzcjNzdGFyK1Jzc3Jhdmcrel9seXNhZ2FyaW4rel90eWFzYWdhcmluK3JldG9mZityZXRkZWYrcWJyZXQrYm93bCtib3dsd2luK2NvYWNoZXhwX3NjaG9vbCtjb2FjaGV4cF90b3RhbCtCaWdUZW4rU0VDK0JpZ1R3ZWx2ZStBQ0MrUGFjVGVuK0JpZ2Vhc3QsIGRhdGEgPSBYX0NGQlJ2ZXJzaW9uUGFjVGVuKSwgZGlyZWN0aW9uID0gYygiYm90aCIpKQpgYGAKCmBgYHtyfQpYX0NGQlJ2ZXJzaW9uQmlnVHdlbHZlIDwtIFhfQ0ZCUnZlcnNpb24gJT4lCiAgZmlsdGVyKEJpZ1R3ZWx2ZSA9PSAxKQojU3RlcHdpc2UgUmVncmVzc2lvbgpzdzwtc3RlcChsbShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcitSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gWF9DRkJSdmVyc2lvbkJpZ1R3ZWx2ZSksIGRpcmVjdGlvbiA9IGMoImJvdGgiKSkKYGBgCgoKU28gdGhyb3VnaCB0aGlzIHByb2Nlc3MsIHdlIGZvdW5kIHRoYXQgZGlmZmVyZW50IHZhcmlhYmxlcyB3ZXJlIGRlZW1lZCBzaWduaWZpY2FudCBpbiBkaWZmZXJlbnQgY29uZmVyZW5jZXMuIEVzc2VudGlhbGx5IGl0IG1lYW5zIHRoYXQgZGlmZmVyZW50IHRoaW5ncyBhcmUgbmVjZXNzYXJ5IHRvIGJlIHN1Y2Nlc3NmdWwgcmVsYXRpdmUgdG8gdGhlIG90aGVyIHRlYW1zIGluIHlvdXIgY29uZmVyZW5jZSwgYmFzZWQgb24gYSBnaXZlbiBjb25mZXJlbmNlLiAKClNFQzogIkZyNXN0YXIiLCJGcjRzdGFyIiwiU280c3RhciIsIlNvYXZnIiwiSnJuYnJyZWNydWl0cyIsIkpyNXN0YXIiLCJKcjRzdGFyIiwiUnNzcjVzdGFyIiwiUnNzcjRzdGFyIiwiel9seXNhZ2FyaW4iLCJjb2FjaGV4cF9zY2hvb2wiLCJjb2FjaGV4cF90b3RhbCIKCkFDQzoiRnJOYnJSZWNydWl0cyIgLCAiRnI0c3RhciIgLCAiU29uYnJyZWNydWl0cyIsICJKcm5icnJlY3J1aXRzIiwgIkpyNXN0YXIiLCAiSnI0c3RhciIsICJKcjNzdGFyIiwgIkpyYXZnIiwgIlJzc3I0c3RhciIsICJ6X2x5c2FnYXJpbiIsInJldG9mZiIsICJib3dsIiAsImNvYWNoZXhwX3RvdGFsIgoKQmlnVGVuOiAiRnJOYnJSZWNydWl0cyIsIkZyM3N0YXIiLCJTbzRzdGFyIiwiSnJuYnJyZWNydWl0cyIsIkpyNXN0YXIiLCJKcjRzdGFyIiwiSnIzc3RhciIsIkpyYXZnIiwiU3JuYnJyZWNydWl0cyIsIlNyM3N0YXIiLCJ6X2x5c2FnYXJpbiIsImNvYWNoZXhwX3RvdGFsIgoKUGFjVGVuOiJGck5iclJlY3J1aXRzIiAsICJGcjRzdGFyIiAsICJTb25icnJlY3J1aXRzIiwgIlNvNHN0YXIiLCAiU29hdmciLCAiSnJuYnJyZWNydWl0cyIgLCAiSnJhdmciICwgIlNyM3N0YXIiICwgIlJzc3JuYnJyZWNydWl0cyIgLCAiUnNzcjVzdGFyIiAsICJSc3NyNHN0YXIiICwgIlJzc3Izc3RhciIgLCAiUnNzcmF2ZyIgLCAiel9seXNhZ2FyaW4iICwgInpfdHlhc2FnYXJpbiIgLCAicmV0ZGVmIiAsICJxYnJldCIgLCAiY29hY2hleHBfc2Nob29sIiAsICJjb2FjaGV4cF90b3RhbCIgLCAiU3JhdmciCiAgICAKQmlnVHdlbHZlOiJGck5iclJlY3J1aXRzIiwgIkZyNHN0YXIiLCAiRnIzc3RhciIsICJGcmF2ZyIsICJTb25icnJlY3J1aXRzIiwiU29hdmciICwgIkpybmJycmVjcnVpdHMiICwgIkpyNXN0YXIiICwgIlNybmJycmVjcnVpdHMiICwgIlJzc3JuYnJyZWNydWl0cyIgLCAiUnNzcmF2ZyIgLCAiel9seXNhZ2FyaW4iICwgImNvYWNoZXhwX3NjaG9vbCIgLCAiY29hY2hleHBfdG90YWwiCgoKTmV4dCwgd2Ugc3Vic2V0dGVkIHRoZSBkYXRhIGZvciBlYWNoIGNvbmZlcmVuY2Ugc28gaXQgb25seSBjb250YWluZWQgdGhlIHZhcmlhYmxlcyB0aGF0IHdlcmUgZGVlbWVkIGltcG9ydGFudCBpbiB0aGUgdmFyaWFibGUgc2NyZWVuaW5nIHByb2Nlc3MuIAoKVGhpcyBmYWNpbGl0YXRlZCB0aGUgcHJvY2VzcyBvZiBjcmVhdGluZyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCB0YWtlIGluIGEgc3RyaW5nIGFzIGEgY29uZmVyZW5jZSAoaS5lLiAiU0VDIikgYW5kIGEgeWVhciBhbmQgb3V0cHV0cyB0aGF0IGNvbmZlcmVuY2UncyByYW5raW5ncyBmb3IgdGhhdCB5ZWFyIAoKVGhlIGZ1bmN0aW9uIHN1YnNldHMgdGhlIGRhdGEgaW50byB0aGUgY29uZmVyZW5jZSB5b3Ugc3BlY2lmeSwgYW5kIHRoZW4gc3Vic2V0cyBpdCBpbnRvIDIgZGF0YXNldHM6IG9uZSB0aGF0IGNvbnRhaW5zIGFsbCB0aGUgZGF0YSBmcm9tIGV2ZXJ5IHllYXIgZXhjZXB0IHRoZSB5ZWFyIHlvdSBzcGVjaWZpZWQgKHRoaXMgaXMgeW91ciB0cmFpbmluZyBkYXRhKSwgYW5kIG9uZSB0aGF0IGlzIHNvbGVseSB0aGUgZGF0YSBvZiB5ZWFyIHlvdSBzcGVjaWZpZWQgKHRoaXMgaXMgeW91ciB0ZXN0IGRhdGEpLiBUaGUgbXVsdGxpcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGlzIGZpdCBiYXNlZCBvbiB0aGUgdHJhaW5pbmcgZGF0YSwgYW5kIHRoZW4geW91IHVzZSB0aGF0IG1vZGVsIHRvIHByZWRpY3QgdGhlIHRlc3QgZGF0YS4gCgoKCmBgYHtyfQpTRUNzdWJzZXQgPC0gYXMuZGF0YS5mcmFtZShYX0NGQlJ2ZXJzaW9uWyxjKDEsMiwzLDcsOCwxNCwxNiwxOCwxOSwyMCwzMSwzMiwzOCw0Niw0Nyw1MCldKQogU0VDc3Vic2V0PC0gU0VDc3Vic2V0ICU+JQogICBmaWx0ZXIoU0VDID09IDEpCkFDQ3N1YnNldCA8LSBhcy5kYXRhLmZyYW1lKFhfQ0ZCUnZlcnNpb25bLGMoMSwyLDMsNiw4LDEyLDE4LDE5LDIwLDIxLDIyLDMyLDM4LDQxLDQ0LDQ3LDUyKV0pCiBBQ0NzdWJzZXQ8LSBBQ0NzdWJzZXQgJT4lCiAgIGZpbHRlcihBQ0MgPT0gMSkKUEFDMTBzdWJzZXQgPC0gYXMuZGF0YS5mcmFtZShYX0NGQlJ2ZXJzaW9uWyxjKDEsMiwzLDYsOCwxMiwxNCwxNiwxOCwyMiwyNywzMCwzMSwzMiwzMywzNCwzOCw0MCw0Miw0Myw0Niw0NywyOCw1MyldKSAKUEFDMTBzdWJzZXQ8LSBQQUMxMHN1YnNldCAlPiUKICAgZmlsdGVyKFBhY1RlbiA9PSAxKQpCaWcxMHN1YnNldCA8LSBhcy5kYXRhLmZyYW1lKFhfQ0ZCUnZlcnNpb25bLGMoMSwyLDMsNiw5LDE0LDE4LDE5LDIwLDIxLDIyLDI0LDI3LDM4LDQ3LDQ5KV0pCiBCaWcxMHN1YnNldDwtIEJpZzEwc3Vic2V0ICU+JQogICBmaWx0ZXIoQmlnVGVuID09IDEpCkJpZzEyc3Vic2V0IDwtIGFzLmRhdGEuZnJhbWUoWF9DRkJSdmVyc2lvblssYygxLDIsMyw2LDgsOSwxMCwxMiwxNiwxOCwxOSwyNCwzMCwzNCwzOCw0Niw0Nyw1MSldKQogQmlnMTJzdWJzZXQ8LSBCaWcxMnN1YnNldCAlPiUKICAgZmlsdGVyKEJpZ1R3ZWx2ZSA9PSAxKQoKcHJlZFJhbms8LSBmdW5jdGlvbih4LHkpCnsKICBkYXQ8LXN1YnNldChTRUNzdWJzZXQsIFNFQ3N1YnNldCRZZWFyICE9IHkpCiAgbmV3ZGF0PC1zdWJzZXQoU0VDc3Vic2V0LCBTRUNzdWJzZXQkWWVhciA9PSB5KQogIGlmKHg9PSJTRUMiKSB7CiAgICBjb2xuYW1lcyhkYXQpIDwtIGMoIlRlYW0iLCJZZWFyIiwiRVBTTnJhbmsiLCJGcjVzdGFyIiwiRnI0c3RhciIsIlNvNHN0YXIiLCJTb2F2ZyIsIkpybmJycmVjcnVpdHMiLCJKcjVzdGFyIiwiSnI0c3RhciIsIlJzc3I1c3RhciIsIlJzc3I0c3RhciIsInpfbHlzYWdhcmluIiwiY29hY2hleHBfc2Nob29sIiwiY29hY2hleHBfdG90YWwiKQogICAgc3c8LSBsbShFUFNOcmFuayB+IEZyNXN0YXIgKyBGcjRzdGFyICsgU280c3RhciArIFNvYXZnICsgSnJuYnJyZWNydWl0cyArIAogICAgSnI1c3RhciArIEpyNHN0YXIgKyBSc3NyNXN0YXIgKyBSc3NyNHN0YXIgKyB6X2x5c2FnYXJpbiArIAogICAgY29hY2hleHBfc2Nob29sICsgY29hY2hleHBfdG90YWwsIGRhdGEgPSBkYXQpCiAgICBwcmVkczwtcHJlZGljdChzdywgbmV3ZGF0YSA9IG5ld2RhdCkKICAgIHByZWRzZXQ8LXQocmJpbmQobmV3ZGF0JFRlYW0sbmV3ZGF0JEVQU05yYW5rLHByZWRzKSkKICAgICBwcmVkZGY8LWFzLmRhdGEuZnJhbWUocHJlZHNldCkKICB9CiAgaWYoeD09IkFDQyIpIHsKICAgIGRhdDwtc3Vic2V0KEFDQ3N1YnNldCwgQUNDc3Vic2V0JFllYXIgIT0geSkKICAgIG5ld2RhdDwtc3Vic2V0KEFDQ3N1YnNldCwgQUNDc3Vic2V0JFllYXIgPT0geSkKICAgIGNvbG5hbWVzKGRhdCkgPC0gYygiVGVhbSIsIlllYXIiLCJFUFNOcmFuayIsICJGck5iclJlY3J1aXRzIiAsICJGcjRzdGFyIiAsICJTb25icnJlY3J1aXRzIiwgIkpybmJycmVjcnVpdHMiLCAiSnI1c3RhciIsICJKcjRzdGFyIiwgIkpyM3N0YXIiLCAiSnJhdmciLCAiUnNzcjRzdGFyIiwgInpfbHlzYWdhcmluIiwicmV0b2ZmIiwgImJvd2wiICwiY29hY2hleHBfdG90YWwiKQogIAogICAgZnc8LSBsbShFUFNOcmFuayB+IEZyTmJyUmVjcnVpdHMgKyBGcjRzdGFyICsgU29uYnJyZWNydWl0cyArIEpybmJycmVjcnVpdHMgKyAKICAgIEpyNXN0YXIgKyBKcjRzdGFyICsgSnIzc3RhciArIEpyYXZnICsgUnNzcjRzdGFyICsgel9seXNhZ2FyaW4gKyAKICAgIHJldG9mZiArIGJvd2wgKyBjb2FjaGV4cF90b3RhbCwgZGF0YSA9IGRhdCkKICAgIAogIHByZWRzPC1wcmVkaWN0KGZ3LCBuZXdkYXRhID0gbmV3ZGF0KQogIHByZWRzZXQ8LXQocmJpbmQobmV3ZGF0JFRlYW0sIG5ld2RhdCRFUFNOcmFuayxwcmVkcykpCiAgIHByZWRkZjwtYXMuZGF0YS5mcmFtZShwcmVkc2V0KQogIH0KICBpZih4PT0iQmlnVGVuIil7CiAgICBkYXQ8LXN1YnNldChCaWcxMHN1YnNldCwgQmlnMTBzdWJzZXQkWWVhciAhPSB5KQogICAgbmV3ZGF0PC1zdWJzZXQoQmlnMTBzdWJzZXQsIEJpZzEwc3Vic2V0JFllYXIgPT0geSkKICBjb2xuYW1lcyhkYXQpIDwtIGMoIlRlYW0iLCJZZWFyIiwiRVBTTnJhbmsiLCJGck5iclJlY3J1aXRzIiwiRnIzc3RhciIsIlNvNHN0YXIiLCJKcm5icnJlY3J1aXRzIiwiSnI1c3RhciIsIkpyNHN0YXIiLCJKcjNzdGFyIiwiSnJhdmciLCJTcm5icnJlY3J1aXRzIiwiU3Izc3RhciIsInpfbHlzYWdhcmluIiwiY29hY2hleHBfdG90YWwiKQogIGJ3IDwtIGxtKEVQU05yYW5rIH4gRnJOYnJSZWNydWl0cyArIEZyM3N0YXIgKyBTbzRzdGFyICsgSnJuYnJyZWNydWl0cyArIAogICAgSnI1c3RhciArIEpyNHN0YXIgKyBKcjNzdGFyICsgSnJhdmcgKyBTcm5icnJlY3J1aXRzICsgU3Izc3RhciArIAogICAgel9seXNhZ2FyaW4gKyBjb2FjaGV4cF90b3RhbCwgZGF0YSA9IGRhdCkKICBwcmVkczwtcHJlZGljdChidywgbmV3ZGF0YSA9IG5ld2RhdCkKICBwcmVkc2V0PC10KHJiaW5kKG5ld2RhdCRUZWFtLG5ld2RhdCRFUFNOcmFuayxwcmVkcykpCiAgcHJlZGRmPC1hcy5kYXRhLmZyYW1lKHByZWRzZXQpCiAgfQogIGlmKHg9PSJQYWNUZW4iKXsKICAgIGRhdDwtc3Vic2V0KFBBQzEwc3Vic2V0LCBQQUMxMHN1YnNldCRZZWFyICE9IHkpCiAgICBuZXdkYXQ8LXN1YnNldChQQUMxMHN1YnNldCwgUEFDMTBzdWJzZXQkWWVhciA9PSB5KQogIGNvbG5hbWVzKGRhdCkgPC0gYygiVGVhbSIsIlllYXIiLCJFUFNOcmFuayIsICJGck5iclJlY3J1aXRzIiAsICJGcjRzdGFyIiAsICJTb25icnJlY3J1aXRzIiwgIlNvNHN0YXIiLCAiU29hdmciLCAiSnJuYnJyZWNydWl0cyIgLCAiSnJhdmciICwgIlNyM3N0YXIiICwgIlJzc3JuYnJyZWNydWl0cyIgLCAiUnNzcjVzdGFyIiAsICJSc3NyNHN0YXIiICwgIlJzc3Izc3RhciIgLCAiUnNzcmF2ZyIgLCAiel9seXNhZ2FyaW4iICwgInpfdHlhc2FnYXJpbiIgLCAicmV0ZGVmIiAsICJxYnJldCIgLCAiY29hY2hleHBfc2Nob29sIiAsICJjb2FjaGV4cF90b3RhbCIgLCAKICAgICJTcmF2ZyIpCiAgYncgPC0gbG0oRVBTTnJhbmsgfiBGck5iclJlY3J1aXRzICsgRnI0c3RhciArIFNvbmJycmVjcnVpdHMgKyBTbzRzdGFyICsgCiAgICBTb2F2ZyArIEpybmJycmVjcnVpdHMgKyBKcmF2ZyArIFNyM3N0YXIgKyBSc3NybmJycmVjcnVpdHMgKyAKICAgIFJzc3I1c3RhciArIFJzc3I0c3RhciArIFJzc3Izc3RhciArIFJzc3JhdmcgKyB6X2x5c2FnYXJpbiArIAogICAgel90eWFzYWdhcmluICsgcmV0ZGVmICsgcWJyZXQgKyBjb2FjaGV4cF9zY2hvb2wgKyBjb2FjaGV4cF90b3RhbCArIAogICAgU3JhdmcsIGRhdGEgPSBkYXQpCiAgcHJlZHM8LXByZWRpY3QoYncsIG5ld2RhdGEgPSBuZXdkYXQpCiAgcHJlZHNldDwtdChyYmluZChuZXdkYXQkVGVhbSxuZXdkYXQkRVBTTnJhbmsscHJlZHMpKQogIHByZWRkZjwtYXMuZGF0YS5mcmFtZShwcmVkc2V0KQoKICB9CiAgaWYoeCA9PSJCaWdUd2VsdmUiKXsKICAgIGRhdDwtc3Vic2V0KEJpZzEyc3Vic2V0LCBCaWcxMnN1YnNldCRZZWFyICE9IHkpCiAgICBuZXdkYXQ8LXN1YnNldChCaWcxMnN1YnNldCwgQmlnMTJzdWJzZXQkWWVhciA9PSB5KQogICAgY29sbmFtZXMoZGF0KSA8LSBjKCJUZWFtIiwiWWVhciIsIkVQU05yYW5rIiwiRnJOYnJSZWNydWl0cyIsICJGcjRzdGFyIiwgIkZyM3N0YXIiLCAiRnJhdmciLCAiU29uYnJyZWNydWl0cyIsIlNvYXZnIiAsICJKcm5icnJlY3J1aXRzIiAsICJKcjVzdGFyIiAsICJTcm5icnJlY3J1aXRzIiAsICJSc3NybmJycmVjcnVpdHMiICwgIlJzc3JhdmciICwgInpfbHlzYWdhcmluIiAsICJjb2FjaGV4cF9zY2hvb2wiICwgImNvYWNoZXhwX3RvdGFsIikKICAKICAgIGZ3PC1sbShFUFNOcmFuayB+IEZyTmJyUmVjcnVpdHMgKyBGcjRzdGFyICsgRnIzc3RhciArIEZyYXZnICsgU29uYnJyZWNydWl0cyArIAogICAgU29hdmcgKyBKcm5icnJlY3J1aXRzICsgSnI1c3RhciArIFNybmJycmVjcnVpdHMgKyBSc3NybmJycmVjcnVpdHMgKyAKICAgIFJzc3JhdmcgKyB6X2x5c2FnYXJpbiArIGNvYWNoZXhwX3NjaG9vbCArIGNvYWNoZXhwX3RvdGFsLCBkYXRhID0gZGF0KQogICAgCiAgcHJlZHM8LXByZWRpY3QoZncsIG5ld2RhdGEgPSBuZXdkYXQpCiAgcHJlZHNldDwtdChyYmluZChuZXdkYXQkVGVhbSwgbmV3ZGF0JEVQU05yYW5rLHByZWRzKSkKICAgcHJlZGRmPC1hcy5kYXRhLmZyYW1lKHByZWRzZXQpCiAgfQogICBwcmVkZGYkVjI8LWFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHByZWRkZiRWMikpCiAgcHJlZGRmJHByZWRzPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkZGYkcHJlZHMpKQogIAogcmV0dXJuKHByZWRkZikKfQpgYGAKCk5leHQsIHdlIHByZWRpY3RlZCB0aGUgY29uZmVyZW5jZSByYW5raW5ncyBmb3IgdGhlIDIwMTggc2Vhc29uIHVzaW5nIHRoZSBmdW5jdGlvbiB3ZSBjcmVhdGVkIGFib3ZlLiBUaGUgcmVzdWx0cyBhcmUgYmVsb3cuIE9uZSBsaW1pdGF0aW9uIGlzIHRoYXQgdGhlIGZ1bmN0aW9uIHByZWRpY3RlZCB0aGUgcmFua2luZ3MgYXMgZG91YmxlcyBpbnN0ZWFkIG9mIGludGVnZXJzLiBUaGVyZWZvcmUsIHdlIGp1c3Qgb3JkZXJlZCB0aGUgcHJlZGljdGlvbnMgbGVhc3QgdG8gZ3JlYXRlc3QsIGFzIHlvdSBjYW4gc2VlIGJlbG93LiAKCgpgYGB7cn0KU0VDPC1wcmVkUmFuaygiU0VDIiwyMDE4KQpBQ0M8LXByZWRSYW5rKCJBQ0MiLDIwMTgpCkJpZ1RlbjwtcHJlZFJhbmsoIkJpZ1RlbiIsMjAxOCkKUGFjVGVuPC1wcmVkUmFuaygiUGFjVGVuIiwyMDE4KQpCaWdUd2VsdmU8LXByZWRSYW5rKCJCaWdUd2VsdmUiLDIwMTgpCgpTRUM8LVNFQ1tvcmRlcihTRUMkcHJlZHMpLF0KU0VDCkFDQzwtQUNDW29yZGVyKEFDQyRwcmVkcyksXQpBQ0MKQmlnVGVuPC1CaWdUZW5bb3JkZXIoQmlnVGVuJHByZWRzKSxdCkJpZ1RlbgpQYWNUZW48LVBhY1RlbltvcmRlcihQYWNUZW4kcHJlZHMpLF0KUGFjVGVuCkJpZ1R3ZWx2ZTwtQmlnVHdlbHZlW29yZGVyKEJpZ1R3ZWx2ZSRwcmVkcyksXQpCaWdUd2VsdmUKYGBgCk91ciBwcmVkaWN0aW9ucyB3ZXJlbid0IHZlcnkgYWNjdWFyYXRlLCBob3dldmVyIHVzdWFsbHkgdGhlIHByZWRpY3RlZCB0b3AgcmFua2VkIHRlYW0gaXMgaW4gdGhlIHRvcCA1IChpc2gpLiAKCldlIGFsc28gdXNlZCBhbm90aGVyIG1ldGhvZCBvZiBwcmVkaWN0aW5nLCBkZWNpc2lvbiB0cmVlcy4gV2Ugd3JvdGUgYSB2ZXJ5IHNpbWlsYXIgZnVuY3Rpb24gdG8gcHJlZGljdCBhIGdpdmVuIHNlYXNvbnMgY29uZmVyZW5jZSByYW5raW5ncyBmb3IgZWFjaCBjb25mZXJlbmNlLiBUaGUgZnVuY3Rpb24gdGFrZXMgaW4gYSBzdHJpbmcgYXMgYSBjb25mZXJlbmNlIChpLmUuICJTRUMiKSBhbmQgYSB5ZWFyIGFuZCBwcmVkaWN0cyB0aGF0IGNvbmZlcmVuY2UncyByYW5raW5ncyBmb3IgdGhhdCB5ZWFyLCBqdXN0IGxpa2UgdGhlIG9uZSBhYm92ZSBidXQgYmFzZWQgb24gdGhlIGRlY2lzaW9uIHRyZWUgbW9kZWwuCgpUaGVyZSBpcyBhIG5ldyBkZWNpc2lvbiB0cmVlIGNyZWF0ZWQgZm9yIGVhY2ggY29uZmVyZW5jZS4gVGhlIHByb2Nlc3MgZm9yIHRoaXMgZnVuY3Rpb24gaXMgZXNzZW50aWFsbHkgdGhlIGV4YWN0IHNhbWUgYXMgdGhlIG9uZSBhYm92ZSwgZXhjZXB0IGRlY2lzaW9uIHRyZWVzIGFyZSB1c2VkIHRvIHByZWRpY3QuIAoKT25lIHRoaW5nIHRvIG5vdGUgYWJvdXQgdGhlIHRyZWUgZGlhZ3JhbSBpcyB0aGF0IGl0IHByZWRpY3RzIHRoZSByYW5raW5nIGluIGZhY3RvcnMgZXNzZW50aWFsbHkuIFRoZXJlZm9yZSBhIGxvdCBvZiAidGllcyIgc2hvdyB1cCBpbiB0aGUgcHJlZGljdGlvbnMsIGFzIHlvdSB3aWxsIHNlZSBiZWxvdy4gCgoKYGBge3J9CnRyZWVQcmVkUmFuazwtIGZ1bmN0aW9uKHgseSkgewogIGlmKHggPT0gIlNFQyIpewogICAgIHRyYWluPC0gIHN1YnNldChYX0NGQlJ2ZXJzaW9uU0VDLCBYX0NGQlJ2ZXJzaW9uU0VDJFllYXIgIT0geSkKICAgICB0ZXN0PC0gc3Vic2V0KFhfQ0ZCUnZlcnNpb25TRUMsIFhfQ0ZCUnZlcnNpb25TRUMkWWVhciA9PSB5KQptb2RlbF90cmVlIDwtdHJlZShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcisgUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IHRyYWluKQpwbG90KG1vZGVsX3RyZWUpCnRleHQobW9kZWxfdHJlZSxjZXg9LjcpCnByZWQgPC0gcHJlZGljdChtb2RlbF90cmVlLG5ld2RhdGEgPSB0ZXN0KQpwcmVkdnNhY3Q8LSB0KHJiaW5kKHByZWQsdGVzdCRFUFNOcmFuaywgdGVzdCRUZWFtKSkKcHJlZHZzYWN0PC1hcy5kYXRhLmZyYW1lKHByZWR2c2FjdCkKcHJlZHZzYWN0JFYyPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkVjIpKQpwcmVkdnNhY3QkcHJlZDwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JHByZWQpKQoKICB9CiAgIGlmKHggPT0gIkFDQyIpewogICAgIHRyYWluPC0gIHN1YnNldChYX0NGQlJ2ZXJzaW9uQUNDLCBYX0NGQlJ2ZXJzaW9uQUNDJFllYXIgIT0geSkKICAgICB0ZXN0PC0gc3Vic2V0KFhfQ0ZCUnZlcnNpb25BQ0MsIFhfQ0ZCUnZlcnNpb25BQ0MkWWVhciA9PSB5KQptb2RlbF90cmVlIDwtdHJlZShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcisgUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IHRyYWluKQpwbG90KG1vZGVsX3RyZWUpCnRleHQobW9kZWxfdHJlZSxjZXg9LjcpCnByZWQgPC0gcHJlZGljdChtb2RlbF90cmVlLG5ld2RhdGEgPSB0ZXN0KQpwcmVkdnNhY3Q8LSB0KHJiaW5kKHByZWQsdGVzdCRFUFNOcmFuaywgdGVzdCRUZWFtKSkKcHJlZHZzYWN0PC1hcy5kYXRhLmZyYW1lKHByZWR2c2FjdCkKcHJlZHZzYWN0JFYyPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkVjIpKQpwcmVkdnNhY3QkcHJlZDwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JHByZWQpKQoKICAgfQogICBpZih4ID09ICJCaWdUZW4iKXsKICAgICB0cmFpbjwtICBzdWJzZXQoWF9DRkJSdmVyc2lvbkJpZ1RlbiwgWF9DRkJSdmVyc2lvbkJpZ1RlbiRZZWFyICE9IHkpCiAgICAgdGVzdDwtIHN1YnNldChYX0NGQlJ2ZXJzaW9uQmlnVGVuLCBYX0NGQlJ2ZXJzaW9uQmlnVGVuJFllYXIgPT0geSkKbW9kZWxfdHJlZSA8LXRyZWUoRVBTTnJhbmt+RnJOYnJSZWNydWl0cytGcjVzdGFyK0ZyNHN0YXIrRnIzc3RhcitGcmF2ZytTb25icnJlY3J1aXRzK1NvNXN0YXIrU280c3RhcitTbzNzdGFyK1NvYXZnK0pybmJycmVjcnVpdHMrSnI1c3RhcitKcjRzdGFyK0pyM3N0YXIrSnJhdmcrU3JuYnJyZWNydWl0cytTcjVzdGFyK1NyNHN0YXIrU3Izc3RhcitTcmF2ZytSc3NybmJycmVjcnVpdHMrUnNzcjVzdGFyK1Jzc3I0c3RhcitSc3NyM3N0YXIrIFJzc3Jhdmcrel9seXNhZ2FyaW4rel90eWFzYWdhcmluK3JldG9mZityZXRkZWYrcWJyZXQrYm93bCtib3dsd2luK2NvYWNoZXhwX3NjaG9vbCtjb2FjaGV4cF90b3RhbCtCaWdUZW4rU0VDK0JpZ1R3ZWx2ZStBQ0MrUGFjVGVuK0JpZ2Vhc3QsIGRhdGEgPSB0cmFpbikKcGxvdChtb2RlbF90cmVlKQp0ZXh0KG1vZGVsX3RyZWUsY2V4PS43KQpwcmVkIDwtIHByZWRpY3QobW9kZWxfdHJlZSxuZXdkYXRhID0gdGVzdCkKcHJlZHZzYWN0PC0gdChyYmluZChwcmVkLHRlc3QkRVBTTnJhbmssIHRlc3QkVGVhbSkpCnByZWR2c2FjdDwtYXMuZGF0YS5mcmFtZShwcmVkdnNhY3QpCnByZWR2c2FjdCRWMjwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JFYyKSkKcHJlZHZzYWN0JHByZWQ8LWFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHByZWR2c2FjdCRwcmVkKSkKCiAgIH0KICAgaWYoeCA9PSAiQmlnVHdlbHZlIil7CiAgICAgdHJhaW48LSAgc3Vic2V0KFhfQ0ZCUnZlcnNpb25CaWdUd2VsdmUsIFhfQ0ZCUnZlcnNpb25CaWdUd2VsdmUkWWVhciAhPSB5KQogICAgIHRlc3Q8LSBzdWJzZXQoWF9DRkJSdmVyc2lvbkJpZ1R3ZWx2ZSwgWF9DRkJSdmVyc2lvbkJpZ1R3ZWx2ZSRZZWFyID09IHkpCm1vZGVsX3RyZWUgPC10cmVlKEVQU05yYW5rfkZyTmJyUmVjcnVpdHMrRnI1c3RhcitGcjRzdGFyK0ZyM3N0YXIrRnJhdmcrU29uYnJyZWNydWl0cytTbzVzdGFyK1NvNHN0YXIrU28zc3RhcitTb2F2ZytKcm5icnJlY3J1aXRzK0pyNXN0YXIrSnI0c3RhcitKcjNzdGFyK0pyYXZnK1NybmJycmVjcnVpdHMrU3I1c3RhcitTcjRzdGFyK1NyM3N0YXIrU3JhdmcrUnNzcm5icnJlY3J1aXRzK1Jzc3I1c3RhcitSc3NyNHN0YXIrUnNzcjNzdGFyKyBSc3NyYXZnK3pfbHlzYWdhcmluK3pfdHlhc2FnYXJpbityZXRvZmYrcmV0ZGVmK3FicmV0K2Jvd2wrYm93bHdpbitjb2FjaGV4cF9zY2hvb2wrY29hY2hleHBfdG90YWwrQmlnVGVuK1NFQytCaWdUd2VsdmUrQUNDK1BhY1RlbitCaWdlYXN0LCBkYXRhID0gdHJhaW4pCnBsb3QobW9kZWxfdHJlZSkKdGV4dChtb2RlbF90cmVlLGNleD0uNykKcHJlZCA8LSBwcmVkaWN0KG1vZGVsX3RyZWUsbmV3ZGF0YSA9IHRlc3QpCnByZWR2c2FjdDwtIHQocmJpbmQocHJlZCx0ZXN0JEVQU05yYW5rLCB0ZXN0JFRlYW0pKQpwcmVkdnNhY3Q8LWFzLmRhdGEuZnJhbWUocHJlZHZzYWN0KQpwcmVkdnNhY3QkVjI8LWFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHByZWR2c2FjdCRWMikpCnByZWR2c2FjdCRwcmVkPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkcHJlZCkpCgogICB9CiAgIGlmKHggPT0gIlBhY1RlbiIpewogICAgIHRyYWluPC0gIHN1YnNldChYX0NGQlJ2ZXJzaW9uUGFjVGVuLCBYX0NGQlJ2ZXJzaW9uUGFjVGVuJFllYXIgIT0geSkKICAgICB0ZXN0PC0gc3Vic2V0KFhfQ0ZCUnZlcnNpb25QYWNUZW4sIFhfQ0ZCUnZlcnNpb25QYWNUZW4kWWVhciA9PSB5KQptb2RlbF90cmVlIDwtdHJlZShFUFNOcmFua35Gck5iclJlY3J1aXRzK0ZyNXN0YXIrRnI0c3RhcitGcjNzdGFyK0ZyYXZnK1NvbmJycmVjcnVpdHMrU281c3RhcitTbzRzdGFyK1NvM3N0YXIrU29hdmcrSnJuYnJyZWNydWl0cytKcjVzdGFyK0pyNHN0YXIrSnIzc3RhcitKcmF2ZytTcm5icnJlY3J1aXRzK1NyNXN0YXIrU3I0c3RhcitTcjNzdGFyK1NyYXZnK1Jzc3JuYnJyZWNydWl0cytSc3NyNXN0YXIrUnNzcjRzdGFyK1Jzc3Izc3RhcisgUnNzcmF2Zyt6X2x5c2FnYXJpbit6X3R5YXNhZ2FyaW4rcmV0b2ZmK3JldGRlZitxYnJldCtib3dsK2Jvd2x3aW4rY29hY2hleHBfc2Nob29sK2NvYWNoZXhwX3RvdGFsK0JpZ1RlbitTRUMrQmlnVHdlbHZlK0FDQytQYWNUZW4rQmlnZWFzdCwgZGF0YSA9IHRyYWluKQpwbG90KG1vZGVsX3RyZWUpCnRleHQobW9kZWxfdHJlZSxjZXg9LjcpCnByZWQgPC0gcHJlZGljdChtb2RlbF90cmVlLG5ld2RhdGEgPSB0ZXN0KQpwcmVkdnNhY3Q8LSB0KHJiaW5kKHByZWQsdGVzdCRFUFNOcmFuaywgdGVzdCRUZWFtKSkKcHJlZHZzYWN0PC1hcy5kYXRhLmZyYW1lKHByZWR2c2FjdCkKcHJlZHZzYWN0JFYyPC1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkdnNhY3QkVjIpKQpwcmVkdnNhY3QkcHJlZDwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZHZzYWN0JHByZWQpKQoKICB9CiAgcmV0dXJuKHByZWR2c2FjdCkKfQoKClNFQ1RyZWU8LXRyZWVQcmVkUmFuaygiU0VDIiwyMDE4KQpBQ0NUcmVlPC10cmVlUHJlZFJhbmsoIkFDQyIsMjAxOCkKQmlnVGVuVHJlZTwtdHJlZVByZWRSYW5rKCJCaWdUZW4iLDIwMTgpClBhY1RlblRyZWU8LXRyZWVQcmVkUmFuaygiUGFjVGVuIiwyMDE4KQpCaWdUd2VsdmVUcmVlPC10cmVlUHJlZFJhbmsoIkJpZ1R3ZWx2ZSIsMjAxOCkKClNFQ1RyZWU8LVNFQ1RyZWVbb3JkZXIoU0VDVHJlZSRwcmVkKSxdClNFQ1RyZWUKQUNDVHJlZTwtQUNDVHJlZVtvcmRlcihBQ0NUcmVlJHByZWQpLF0KQUNDVHJlZQpCaWdUZW5UcmVlPC1CaWdUZW5UcmVlW29yZGVyKEJpZ1RlblRyZWUkcHJlZCksXQpCaWdUZW5UcmVlClBhY1RlblRyZWU8LVBhY1RlblRyZWVbb3JkZXIoUGFjVGVuVHJlZSRwcmVkKSxdClBhY1RlblRyZWUKQmlnVHdlbHZlVHJlZTwtQmlnVHdlbHZlVHJlZVtvcmRlcihCaWdUd2VsdmVUcmVlJHByZWQpLF0KQmlnVHdlbHZlVHJlZQoKCgpgYGAKClRoZXNlIHByZWRpY2l0aW9ucyBhcmUgYWxzbyBub3QgdmVyeSBhY2N1cmF0ZS4gSG93ZXZlciwgdGhlIHRpZXMgYXJlIGludGVyZXN0aW5nIGJlY2F1c2UgeW91IGNhbiBzZWUgaG93IHRlYW1zIGRpZmZlciBpbiB0aGUgcG9zdC1zZWFzb24gdGhhdCB3ZXJlIHByZWRpY3RlZCB0byBwZXJmb3JtIHRoZSBzYW1lLiAKCk92ZXJhbGwsIHByZXNlYXNvbiBzdGF0aXN0aWNzIGRvbnQgc2VlbSB0byBiZSBhIHZlcnkgZ29vZCBwcmVkaWN0b3Igb2YgcG9zdC1zZWFzb24gY29uZmVyZW5jZSByYW5raW5ncywgd2hldGhlciB5b3UgYXJlIHVzaW5nIG11bHRpbHBsZSBsaW5lYXIgcmVncmVzc2lvbiBhbmQgdmFyaWFibGUgc2NyZWVuaW5nIG1ldGhvZHMgb3IgZGVjaXNpb24gdHJlZXMuCgpBbiBpbXBvcnRhbnQgcmVzdWx0IHdlIGF0dGFpbmVkIHdhcyBob3cgZGlmZmVyZW50IGNvbmZlcmVuY2VzIHlpZWxkIGRpZmZlcmVudCBwcmVkaWN0b3JzIG9mIHN1Y2Nlc3MuIAo=